package com.ssyt.wxstore.common;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;

import com.ssyt.wxstore.common.util.ValidateUtil;

/**
 * 公共的Dao，最好让所有的Dao继承这个类
 * 
 * @author Administrator
 * @since 2016年12月10日
 */
@SuppressWarnings("unchecked")
public class BaseDao<T, P extends Serializable> {

	@Autowired
	private SessionFactory sessionFactory;
	private Class<T> entityClass;

	public BaseDao() {
		// 通过泛型得到class对象
		ParameterizedType parameterizedType = (ParameterizedType) getClass()
				.getGenericSuperclass();
		Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
		entityClass = (Class<T>) actualTypeArguments[0];
	}

	/**
	 * 获取Session
	 * 
	 * @return
	 */
	public Session getSession() {
		// return sessionFactory.openSession();
		return sessionFactory.getCurrentSession();
	}

	/**
	 * 新增
	 * 
	 * @param t
	 *            保存的对象
	 * @return 当前新增的主键
	 */
	protected P save(T t) {
		ValidateUtil.notNull(t, "参数t不能为空：" + t);

		return (P) getSession().save(t);
	}

	/**
	 * 修改
	 * 
	 * @param t
	 * @return
	 */
	protected void update(T t) {
		ValidateUtil.notNull(t, "参数t不能为空：" + t);

		getSession().update(t);
	}

	/**
	 * 使用Hql修改
	 * 
	 * @param t
	 * @return
	 */
	protected int updateByHql(String hql, List<Object> paramList) {
		ValidateUtil.notNull(hql, "参数hql不能为空：" + hql);

		Query<T> query = getSession().createQuery(hql);
		setParameterByHql(query, paramList);
		return query.executeUpdate();
	}

	protected int updateByHql(String hql, Object... params) {
		return updateByHql(hql, Arrays.asList(params));
	}

	/**
	 * 删除
	 * 
	 * @param t
	 * @return
	 */
	protected void delete(T t) {
		ValidateUtil.notNull(t, "参数t不能为空：" + t);

		getSession().delete(t);
	}

	/**
	 * get查询
	 * 
	 * @param t
	 * @return
	 */
	protected T get(P p) {
		ValidateUtil.notNull(p, "参数p不能为空：" + p);

		return (T) getSession().get(entityClass, p);
	}

	/**
	 * load查询
	 * 
	 * @param t
	 * @return
	 */
	protected T load(P p) {
		ValidateUtil.notNull(p, "参数p不能为空：" + p);

		return (T) getSession().load(entityClass, p);
	}

	/**
	 * 通过HQL查询得到单个结果（查询所有属性，如：FROM User）
	 * 
	 * @param hql
	 * @param paramList
	 * @return
	 */
	protected T uniqueEntityByHql(String hql, List<Object> paramList) {
		ValidateUtil.notBlank(hql, "参数hql不能为空：" + hql);

		Query<T> query = getSession().createQuery(hql, entityClass);
		setParameterByHql(query, paramList);

		return query.setMaxResults(1).getSingleResult();
	}

	protected T uniqueEntityByHql(String hql, Object... params) {
		return uniqueEntityByHql(hql, Arrays.asList(params));
	}

	/**
	 * 通过HQL查询得到单个结果（查询单属性，如：SELECT username FROM User）
	 * 
	 * @param hql
	 * @param paramList
	 * @return
	 */
	protected <E> E uniqueSinglePropertyByHql(Class<E> e, String hql,
			List<Object> paramList) {
		ValidateUtil.notBlank(hql, "参数hql不能为空：" + hql);

		Query<E> query = getSession().createQuery(hql, e);
		setParameterByHql(query, paramList);

		return query.setMaxResults(1).getSingleResult();
	}

	protected <E> E uniqueSinglePropertyByHql(Class<E> e, String hql,
			Object... params) {
		return uniqueSinglePropertyByHql(e, hql, Arrays.asList(params));
	}

	/**
	 * 通过HQL查询得到单个结果（查询多属性，如：SELECT username, password FROM User || FROM User u,
	 * Log l WHERE u.id=l.user_id）
	 * 
	 * @param hql
	 * @param paramList
	 * @return
	 */
	protected Object[] uniqueMultiPropertyByHql(String hql,
			List<Object> paramList) {
		ValidateUtil.notBlank(hql, "参数hql不能为空：" + hql);

		Query<Object[]> query = getSession().createQuery(hql, Object[].class);
		setParameterByHql(query, paramList);

		return query.setMaxResults(1).getSingleResult();
	}

	protected Object[] uniqueMultiPropertyByHql(String hql, Object... params) {
		return uniqueMultiPropertyByHql(hql, Arrays.asList(params));
	}

	/**
	 * 通过HQL查询得到多个结果（如：FROM User）
	 * 
	 * @param hql
	 * @param paramList
	 * @return
	 */
	protected List<T> listEntityByHql(String hql, List<Object> paramList) {
		ValidateUtil.notBlank(hql, "参数hql不能为空：" + hql);

		Query<T> query = getSession().createQuery(hql, entityClass);
		setParameterByHql(query, paramList);
		return query.getResultList();
	}

	protected List<T> listEntityByHql(String hql, Object... params) {
		return listEntityByHql(hql, Arrays.asList(params));
	}

	/**
	 * 通过HQL查询得到多个结果（查询单属性，如：SELECT username FROM User）
	 * 
	 * @param hql
	 * @param paramList
	 * @return
	 */
	protected <E> List<E> listSinglePropertyByHql(Class<E> e, String hql,
			List<Object> paramList) {
		ValidateUtil.notBlank(hql, "参数hql不能为空：" + hql);

		Query<E> query = getSession().createQuery(hql, e);
		setParameterByHql(query, paramList);

		return query.getResultList();
	}

	protected <E> List<E> listSinglePropertyByHql(Class<E> e, String hql,
			Object... params) {
		return listSinglePropertyByHql(e, hql, Arrays.asList(params));
	}

	/**
	 * 通过HQL查询得到多个结果（查询多属性，如：SELECT username, password FROM User || FROM User u,
	 * Log l WHERE u.id=l.user_id）
	 * 
	 * @param hql
	 * @param paramList
	 * @return
	 */
	protected List<Object[]> listMultiPropertyByHql(String hql,
			List<Object> paramList) {
		ValidateUtil.notBlank(hql, "参数hql不能为空：" + hql);

		Query<Object[]> query = getSession().createQuery(hql, Object[].class);
		setParameterByHql(query, paramList);

		return query.getResultList();
	}

	protected List<Object[]> listMultiPropertyByHql(String hql,
			Object... params) {
		return listMultiPropertyByHql(hql, Arrays.asList(params));
	}

	/**
	 * 通过HQL分页查询（查询所有属性，如：FROM User）
	 * 
	 * @param pageNo
	 * @param pageSize
	 * @param hql
	 * @param paramList
	 * @return
	 */
	protected PageModel<T> pageEntityByHql(int pageNo, int pageSize,
			String hql, List<Object> paramList) {
		ValidateUtil.isTrue(pageNo > 0, "参数pageNo不能 <= 0：" + pageNo);
		ValidateUtil.isTrue(pageSize > 0, "参数pageSize不能 <= 0：" + pageSize);
		ValidateUtil.notBlank(hql, "参数hql不能为空：" + hql);

		Query<T> query = getSession().createQuery(hql, entityClass);
		setParameterByHql(query, paramList);
		query.setFirstResult((pageNo - 1) * pageSize);
		query.setMaxResults(pageSize);
		List<T> list = query.getResultList();

		hql = "SELECT COUNT(*) "
				+ hql.substring(StringUtils.indexOfIgnoreCase(hql, "FROM"));
		long count = uniqueSinglePropertyByHql(Long.class, hql, paramList);

		return new PageModel<T>(list, count, pageNo, pageSize);
	}

	protected PageModel<T> pageEntityByHql(int pageNo, int pageSize,
			String hql, Object... params) {
		return pageEntityByHql(pageNo, pageSize, hql, Arrays.asList(params));
	}

	/**
	 * 通过HQL分页查询（查询单个属性，如：SELECT username FROM User）
	 * 
	 * @param pageNo
	 * @param pageSize
	 * @param hql
	 * @param paramList
	 * @return
	 */
	protected <E> PageModel<E> pageSinglePropertyByHql(Class<E> e, int pageNo,
			int pageSize, String hql, List<Object> paramList) {
		ValidateUtil.isTrue(pageNo > 0, "参数pageNo不能 <= 0：" + pageNo);
		ValidateUtil.isTrue(pageSize > 0, "参数pageSize不能 <= 0：" + pageSize);
		ValidateUtil.notBlank(hql, "参数hql不能为空：" + hql);

		Query<E> query = getSession().createQuery(hql, e);
		setParameterByHql(query, paramList);
		query.setFirstResult((pageNo - 1) * pageSize);
		query.setMaxResults(pageSize);
		List<E> list = query.getResultList();

		hql = "SELECT COUNT(*) "
				+ hql.substring(StringUtils.indexOfIgnoreCase(hql, "FROM"));
		long count = uniqueSinglePropertyByHql(Long.class, hql, paramList);

		return new PageModel<E>(list, count, pageNo, pageSize);
	}

	protected <E> PageModel<E> pageSinglePropertyByHql(Class<E> e, int pageNo,
			int pageSize, String hql, Object... params) {
		return pageSinglePropertyByHql(e, pageNo, pageSize, hql,
				Arrays.asList(params));
	}

	/**
	 * 通过HQL分页查询（查询多个属性，如：SELECT username, password FROM User || FROM User u,
	 * Log l WHERE u.id=l.user_id）
	 * 
	 * @param pageNo
	 * @param pageSize
	 * @param hql
	 * @param paramList
	 * @return
	 */
	protected PageModel<Object[]> pageMultiPropertyByHql(int pageNo,
			int pageSize, String hql, List<Object> paramList) {
		ValidateUtil.isTrue(pageNo > 0, "参数pageNo不能 <= 0：" + pageNo);
		ValidateUtil.isTrue(pageSize > 0, "参数pageSize不能 <= 0：" + pageSize);
		ValidateUtil.notBlank(hql, "参数hql不能为空：" + hql);

		Query<Object[]> query = getSession().createQuery(hql, Object[].class);
		setParameterByHql(query, paramList);
		query.setFirstResult((pageNo - 1) * pageSize);
		query.setMaxResults(pageSize);
		List<Object[]> list = query.getResultList();

		hql = "SELECT COUNT(*) "
				+ hql.substring(StringUtils.indexOfIgnoreCase(hql, "FROM"));
		long count = uniqueSinglePropertyByHql(Long.class, hql, paramList);

		return new PageModel<Object[]>(list, count, pageNo, pageSize);
	}

	protected PageModel<Object[]> pageMultiPropertyByHql(int pageNo,
			int pageSize, String hql, Object... params) {
		return pageMultiPropertyByHql(pageNo, pageSize, hql,
				Arrays.asList(params));
	}

	/**
	 * 通过SQL查询得到单个结果（查询所有属性，如：FROM user）
	 * 
	 * @param sql
	 * @param paramList
	 * @return
	 */
	protected T uniqueEntityBySql(String sql, List<Object> paramList) {
		ValidateUtil.notBlank(sql, "参数sql不能为空：" + sql);

		Query<T> query = getSession().createNativeQuery(sql, entityClass);
		setParameterBySql(query, paramList);

		return query.setMaxResults(1).getSingleResult();
	}

	protected T uniqueEntityBySql(String sql, Object... params) {
		return uniqueEntityBySql(sql, Arrays.asList(params));
	}

	/**
	 * 通过SQL查询得到单个结果（查询单属性，如：SELECT username FROM user）
	 *
	 * @param sql
	 * @param paramList
	 * @return
	 */
	protected <E> E uniqueSinglePropertyBySql(Class<E> e, String sql,
			List<Object> paramList) {
		ValidateUtil.notBlank(sql, "参数sql不能为空：" + sql);

		// 此处不能指定createNativeQuery的第二个参数！
		Query<E> query = getSession().createNativeQuery(sql);
		setParameterBySql(query, paramList);

		return query.setMaxResults(1).getSingleResult();
	}

	protected <E> E uniqueSinglePropertyBySql(Class<E> e, String sql,
			Object... params) {
		return uniqueSinglePropertyBySql(e, sql, Arrays.asList(params));
	}

	/**
	 * 通过SQL查询得到单个结果（查询多属性，如：SELECT username, password FROM user || SELECT *
	 * FROM user u, log l WHERE u.id=l.user_id）
	 *
	 * @param sql
	 * @param paramList
	 * @return
	 */
	protected Object[] uniqueMultiPropertyBySql(String sql,
			List<Object> paramList) {
		ValidateUtil.notBlank(sql, "参数sql不能为空：" + sql);

		// 此处不能指定createNativeQuery的第二个参数！
		Query<Object[]> query = getSession().createNativeQuery(sql);
		setParameterBySql(query, paramList);

		return query.setMaxResults(1).getSingleResult();
	}

	protected Object[] uniqueMultiPropertyBySql(String sql, Object... params) {
		return uniqueMultiPropertyBySql(sql, Arrays.asList(params));
	}

	/**
	 * 通过SQL查询得到多个结果（如：SELECT * FROM user）
	 *
	 * @param sql
	 * @param paramList
	 * @return
	 */
	protected List<T> listEntityBySql(String sql, List<Object> paramList) {
		ValidateUtil.notBlank(sql, "参数sql不能为空：" + sql);
		Query<T> query = getSession().createNativeQuery(sql, entityClass);
		setParameterBySql(query, paramList);
		return query.getResultList();
	}

	protected List<T> listEntityBySql(String sql, Object... params) {
		return listEntityBySql(sql, Arrays.asList(params));
	}

	/**
	 * 通过SQL查询得到多个结果（查询单属性，如：SELECT username FROM user）
	 *
	 * @param sql
	 * @param paramList
	 * @return
	 */
	protected <E> List<E> listSinglePropertyBySql(Class<E> e, String sql,
			List<Object> paramList) {
		ValidateUtil.notBlank(sql, "参数sql不能为空：" + sql);

		// 此处不能指定createNativeQuery的第二个参数！
		Query<E> query = getSession().createNativeQuery(sql);
		setParameterBySql(query, paramList);

		return query.getResultList();
	}

	protected <E> List<E> listSinglePropertyBySql(Class<E> e, String sql,
			Object... params) {
		return listSinglePropertyBySql(e, sql, Arrays.asList(params));
	}

	/**
	 * 通过SQL查询得到多个结果（查询多属性，如：SELECT username, password FROM user || SELECT *
	 * FROM user u, log l WHERE u.id=l.user_id）
	 *
	 * @param sql
	 * @param paramList
	 * @return
	 */
	protected List<Object[]> listMultiPropertyBySql(String sql,
			List<Object> paramList) {
		ValidateUtil.notBlank(sql, "参数sql不能为空：" + sql);

		// 此处不能指定createNativeQuery的第二个参数！
		Query<Object[]> query = getSession().createNativeQuery(sql);
		setParameterBySql(query, paramList);

		return query.getResultList();
	}

	protected List<Object[]> listMultiPropertyBySql(String sql,
			Object... params) {
		return listMultiPropertyBySql(sql, Arrays.asList(params));
	}

	/**
	 * 通过SQL分页查询（如：SELECT * FROM User）<br>
	 * 注：分页查询时不能使用数据库特有的语法，如limit ?, ?
	 * 
	 * @param pageNo
	 * @param pageSize
	 * @param sql
	 * @param paramList
	 * @return
	 */
	@Deprecated
	protected PageModel<T> pageBySql(int pageNo, int pageSize, String sql,
			List<Object> paramList) {
		ValidateUtil.isTrue(pageNo > 0, "参数pageNo不能 <= 0：" + pageNo);
		ValidateUtil.isTrue(pageSize > 0, "参数pageSize不能 <= 0：" + pageSize);
		ValidateUtil.notBlank(sql, "参数sql不能为空：" + sql);

		Query<T> query = getSession().createNativeQuery(sql, entityClass);
		setParameterBySql(query, paramList);
		query.setFirstResult((pageNo - 1) * pageSize);
		query.setMaxResults(pageSize);
		List<T> list = query.getResultList();

		sql = "SELECT COUNT(*) " + sql.substring(sql.indexOf("FROM"));
		long count = uniqueSinglePropertyBySql(BigInteger.class, sql, paramList)
				.longValue();

		return new PageModel<T>(list, count, pageNo, pageSize);
	}

	@Deprecated
	protected PageModel<T> pageBySql(int pageNo, int pageSize, String sql,
			Object... params) {
		return pageBySql(pageNo, pageSize, sql, Arrays.asList(params));
	}

	/**
	 * Query参数设置
	 * 
	 * @param query
	 * @param paramList
	 */
	public void setParameterByHql(Query<?> query, List<Object> paramList) {
		if (paramList != null && !paramList.isEmpty()) {
			for (int i = 0; i < paramList.size(); i++) {
				query.setParameter(i, paramList.get(i));
			}
		}
	}

	public void setParameterBySql(Query<?> query, List<Object> paramList) {
		if (paramList != null && !paramList.isEmpty()) {
			for (int i = 0; i < paramList.size(); i++) {
				query.setParameter(i + 1, paramList.get(i));
			}
		}
	}
}
